﻿using System;
using System.Collections.Generic;
using System.Device.Location;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Ink;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
using Microsoft.Phone.Shell;
using System.Windows.Media.Imaging;
using System.Collections;
using System.Runtime.Serialization.Json;
using System.Threading;
using Microsoft.Live;
using System.Security.Cryptography;
using System.Diagnostics;
using Microsoft.Phone.Info;

namespace Whiteboard
{
    public partial class MainPage : PhoneApplicationPage
    {
 //       private string strLineCoords;
        private StringBuilder strLineCoords;
        private StringBuilder lineCoords = new StringBuilder();
        private int[] arrCoords = new int [4];
        private List<string> receivedPackets = new List<string>();
        int receivedPkgCount = 999;
        int receivedCount = 0;
        bool isAdmin = false;
        string localEmail;
        int joinedCount = 0;
        bool responseReceived = false;
        public string loggedinUserEmail;
        LiveConnectClient client;
        bool waitingForAcceptance = false;
        Timer waitForAdminTimer;
        private GeoCoordinateWatcher gcw = null;

        // The address of the multicast group to join.
        // Must be in the range from 224.0.0.0 to 239.255.255.255
        private const string GROUP_ADDRESS = "224.0.1.1";

        // The port over which to communicate to the multicast group
        private const int GROUP_PORT = 52274;
        
        // A client receiver for multicast traffic from any source
        UdpAnySourceMulticastClient _client = null;

        /// <summary>
        /// true if we have joined the multicast group; otherwise, false
        /// </summary>
        public bool _joined = false;

        // Buffer for incoming data
        private byte[] _receiveBuffer;

        // Maximum size of a message in this communication
        private const int MAX_MESSAGE_SIZE = 512;

        // Default line coordinate beginning identifier
        private string COORD_BEGIN = "#CORDS#";


        private string LINE_THICK;

        static readonly string[] AccentColors = { "magenta", "purple", "yellow", "cyan", "brown", "gray", "orange", "blue", "red", "green" };

        static readonly string[] LineThickness = { "small", "medium", "large" };
        
        private string LINE_COLOR;

        /// <summary>
        /// Constructor
        /// </summary>
        public MainPage()
        {
            InitializeComponent();

            this.strLineCoords = new StringBuilder();
            this.Accents.DataContext = AccentColors;
            this.Thicknesses.DataContext = LineThickness;

            Random rand = new Random();
            int seed = rand.Next(0, 9);
            LINE_COLOR = AccentColors.ElementAt(seed).ToString();
            this.Accents.SelectedIndex = seed;

            this.ContentPanelCanvas.MouseMove += new MouseEventHandler(ContentPanelCanvas_MouseMove);
            this.ContentPanelCanvas.MouseLeftButtonDown += new MouseButtonEventHandler(ContentPanelCanvas_MouseLeftButtonDown);
            this.wbContextMenu.Visibility = System.Windows.Visibility.Collapsed;

            // Provide the location to the AdControl for better targeting (optional).
            // This is done by starting a GeoCoordinateWatcher and waiting for the location to be available.
            // The callback will set the location into the ad. 
            // Note: The location may not be available in time for the first ad request.
            this.gcw = new GeoCoordinateWatcher();
            this.gcw.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(gcw_PositionChanged);
            this.gcw.Start();


        }

        private void gcw_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            // Stop the GeoCoordinateWatcher now that we have the device location.
            this.gcw.Stop();

            adControl.Latitude = e.Position.Location.Latitude;
            adControl.Longitude = e.Position.Location.Longitude;

        }

        // the drawing code consists of 3 mouse events, button down, mousemove and button up. 
        // the code is picked from http://codeding.com/?article=17

        private bool drawing = false;
        private Point start = new Point();
        private void ContentPanelCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Collapsed;
            drawing = true;
            start = e.GetPosition((UIElement)sender);
            lineCoords.Clear();

            // total prefix for all line attributes: Command + line color + thickness
            string prefix = COORD_BEGIN + LINE_COLOR + "#" + LINE_THICK + "#";
            lineCoords.AppendLine(prefix);
        }

        private void ContentPanelCanvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (drawing && _joined)
            {
                Point current = e.GetPosition((UIElement)sender);
                Line line = new Line() { X1 = start.X, Y1 = start.Y, X2 = current.X, Y2 = current.Y };
                
                //TODO: Instead of appending the coords in a string, a structure needs to be created for this coords 
                //and then should be serialized while sending and deserialized at the receiving end.
                strLineCoords.Clear();
                strLineCoords.Append(start.X.ToString());
                strLineCoords.Append(",");
                strLineCoords.Append(start.Y.ToString());
                strLineCoords.Append(",");
                strLineCoords.Append(current.X.ToString());
                strLineCoords.Append(",");
                strLineCoords.Append(current.Y.ToString());

                //lineCoords.AppendLine(strLineCoords);
                strLineCoords.Append("$");
                lineCoords.Append(strLineCoords);


                if (COORD_BEGIN.Equals("#CORDS#"))
                {
                    line.Stroke = new SolidColorBrush(StringToColor(LINE_COLOR));
                    line.StrokeThickness = StringToThickness(LINE_THICK);
                }
                else
                {
                    line.Stroke = new SolidColorBrush(Colors.White);
                    line.StrokeThickness = StringToThickness(LINE_THICK);
                    line.Cursor = Cursors.Eraser;
                }
                
                ContentPanelCanvas.Children.Add(line);

                start = current;
            }
        }

        private Color StringToColor(string strColor)
        {
            
                Color temp = new Color();
                switch(strColor)
                {
                    case "magenta":
                        temp = Colors.Magenta;
                        break;
                    case "purple":
                        temp = Colors.Purple;
                        break;
                    case "yellow":
                        temp = Colors.Yellow;
                        break;
                    case "cyan":
                        temp = Colors.Cyan;
                        break;
                    case "brown":
                        temp = Colors.Brown;
                        break;
                    case "gray":
                        temp = Colors.Gray;
                        break;
                    case "orange":
                        temp = Colors.Orange;
                        break;
                    case "blue":
                        temp = Colors.Blue;
                        break;
                    case "red":
                        temp = Colors.Red;
                        break;
                     case "green":
                        temp = Colors.Green;
                        break;
                    default: 
                    temp = Colors.Black;
                    break;
                }
                return temp;
        }

        private int StringToThickness(string strThickness)
        {
            int temp = 0; // default

            switch (strThickness)
            {
                case "small":
                    temp = 5;
                    break;
                case "medium":
                    temp = 10;
                    break;
                case "large":
                    temp = 15;
                    break;
                default:
                    temp = 0;
                    break;
            }

            return temp;
        }

        private void ResetCanvas()
        {
             // Always make sure to do this on the UI thread.
            Deployment.Current.Dispatcher.BeginInvoke(
            () =>
            {
                this.ContentPanelCanvas.Children.Clear();
                this.ContentPanelCanvas.Children.Add(BlankRectangle);
            });

            COORD_BEGIN = "#CORDS#";
        }

        private void ContentPanelCanvas_MouseLeave(object sender, MouseEventArgs e)
        {
            if (lineCoords.Length > 0)
            {
                SendString(lineCoords.ToString());
               // Receive();
                lineCoords.Clear();
            }
        }
                      
        private void ContentPanelCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            drawing = false;
        }

     

        /// <summary>
        /// Override the OnNavigatedTo method.
        /// </summary>
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            PhoneApplicationService phoneAppService = PhoneApplicationService.Current;
            loggedinUserEmail = phoneAppService.State["userEmail"].ToString();
            object clientObject;
            if (phoneAppService.State.ContainsKey("client")) 
            { 
                if (phoneAppService.State.TryGetValue("client", out clientObject)) 
                {
                    client = (LiveConnectClient) clientObject;
                    phoneAppService.State.Remove("client");
                } 
            }
            if (!_joined)
            {
                Join();
            }
            // Create a new UdpAnySourceMulticastClient instance and join the group.
            // Join();
        }

        /// <summary>
        /// Create a new UdpAnySourceMulticastClient instance and join the group.
        /// Referred code from http://msdn.microsoft.com/en-us/library/hh286407(v=vs.92).aspx
        /// </summary>
        private void Join()
        {
            // Initialize the receive buffer
            _receiveBuffer = new byte[MAX_MESSAGE_SIZE];

            // Create the UdpAnySourceMulticastClient instance using the defined 
            // GROUP_ADDRESS and GROUP_PORT constants. UdpAnySourceMulticastClient is a 
            // client receiver for multicast traffic from any source, also known as Any Source Multicast (ASM)
            _client = new UdpAnySourceMulticastClient(IPAddress.Parse(GROUP_ADDRESS), GROUP_PORT);

            // Make a request to join the group.
            _client.BeginJoinGroup(
                result =>
                {
                    // Complete the join
                    _client.EndJoinGroup(result);

                    // The MulticastLoopback property controls whether you receive multicast 
                    // packets that you send to the multicast group. Default value is true, 
                    // meaning that you also receive the packets you send to the multicast group. 
                    // To stop receiving these packets, you can set the property following to false
                    _client.MulticastLoopback = true;

                    // Set a flag indicating that we have now joined the multicast group 
                    _joined = true;

                    // Let others know we have joined by sending out a message to the group.
                    StringBuilder message = new StringBuilder("#JOINS#");
                    message.Append(loggedinUserEmail);
                    waitingForAcceptance = true;
                    SendString(message.ToString());

                    // Wait for data from the group. This is an asynchronous operation 
                    // and will not block the UI thread.
                    Receive();

                }, null);
        }

        /// <summary>
        /// Send the given message to the multicast group.
        /// Referred code from http://msdn.microsoft.com/en-us/library/hh286407(v=vs.92).aspx
        /// </summary>
        /// <param name="message">The message to send</param>
        private void SendString(string message)
        {
            // Attempt the send only if you have already joined the group.
            if (_joined)
            {
                int pkgCount = 0;
                int msgbyteLenth = message.Length; // *sizeof(Char);
                if (msgbyteLenth > MAX_MESSAGE_SIZE)
                {
                    
                    StringBuilder strMessage = new StringBuilder(message.TrimEnd());

                    StringBuilder pkgNumber = new StringBuilder("#P000");

                    while (strMessage.Length > 0) // * sizeof(char) > 0)
                    {
                        string numPrefix = "";
                                                
                        if (pkgCount < 10) numPrefix = "00";
                        if (pkgCount >= 10 && pkgCount < 100) numPrefix = "0";
                        pkgNumber = new StringBuilder("#P" + numPrefix + pkgCount.ToString());
                        int removeLength = 0;
                        if (((strMessage.Length) + ( pkgNumber.Length)) < MAX_MESSAGE_SIZE)
                        {
                            // this is a last package
                            removeLength = strMessage.Length;
                            pkgNumber = new StringBuilder("#L" + numPrefix + pkgCount.ToString());
                        }
                        else
                            removeLength = (MAX_MESSAGE_SIZE) - pkgNumber.Length;
                        string strPkg = pkgNumber.Append(strMessage.ToString().Substring(0, removeLength)).ToString();
                        strMessage = new StringBuilder(strMessage.ToString().Substring(removeLength, strMessage.Length - removeLength));
                        byte[] data = Encoding.UTF8.GetBytes(strPkg);
                        _client.BeginSendToGroup(data, 0, data.Length,
                            result =>
                            {
                                _client.EndSendToGroup(result);
                            }, null);

                        pkgCount++;
                        Receive();
                    }
                }
                else
                {
                    byte[] data = Encoding.UTF8.GetBytes(message);
                    _client.BeginSendToGroup(data, 0, data.Length,
                        result =>
                        {
                            _client.EndSendToGroup(result);
                        }, null);
                    Receive();
                }
            }
        }

         /// <summary>
        /// Receive data from the group and log it.
        /// Referred code from http://msdn.microsoft.com/en-us/library/hh286407(v=vs.92).aspx
        /// </summary>
        private void Receive()
        {
            // Only attempt to receive if you have already joined the group
            if (_joined)
            {
                string dataReceived;
                bool finishedReceiving = true;
                _client.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length,
                    result =>
                    {
                        IPEndPoint source;

                        // Complete the asynchronous operation. The source field will 
                        // contain the IP address of the device that sent the message
                        _client.EndReceiveFromGroup(result, out source);

                        // Get the received data from the buffer.
                        dataReceived = Encoding.UTF8.GetString(_receiveBuffer, 0, _receiveBuffer.Length).TrimEnd() ;

                        if (dataReceived.StartsWith("#P") || dataReceived.StartsWith("#L"))
                        {
                            if (dataReceived.StartsWith("#L"))
                                receivedPkgCount = int.Parse(new string(dataReceived.Remove(0, 2).Take(3).ToArray()));
                            receivedPackets.Add(dataReceived.Remove(0, 2).TrimEnd('\0'));

                            finishedReceiving = false;

                            if (receivedCount++ == receivedPkgCount)
                            {
                                StringBuilder dataR = new StringBuilder();
                                receivedPackets.Sort();
                                receivedPackets.ForEach(e => { e.TrimEnd('\0'); dataR.Append(e.Remove(0, 3)); });
                                receivedPackets.ForEach(e => { e = e.TrimEnd('\0');});
                                dataReceived = dataR.ToString().TrimEnd('\0'); 
                                receivedPkgCount = 999;
                                receivedCount = 0;
                                finishedReceiving = true;
                                receivedPackets = new List<string>();
                                Receive();
                            }
                            Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);
                        }

                        if (finishedReceiving)
                        {


                            string message = dataReceived.TrimEnd('\0');
                            if (message.StartsWith("#RESET#"))
                            {
                                ResetCanvas();
                            }

                            if (message.StartsWith("#CORDS#") || message.StartsWith("#ERASE#"))
                            {
                                string lineColor = message.Split('#')[2];
                                string lineThickness = message.Split('#')[3];

                                int[][] lineCoords = ReadReceivedCoordinates(message.Split('#')[4]);

                                bool isDraw = true;
                                if (dataReceived.StartsWith("#ERASE#"))
                                    isDraw = false;


                                foreach (int[] line in lineCoords)
                                {
                                    DrawLine(line, isDraw, lineColor, lineThickness);
                                }

                            }
                            else if (dataReceived.StartsWith("#TEXTS#"))
                            {
                                int x = int.Parse(dataReceived.Split('#')[2]);
                                int y = int.Parse(dataReceived.Split('#')[3]);
                                 // Always make sure to do this on the UI thread.
                                Deployment.Current.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    string content = dataReceived.Split('#')[4].Trim('\0');
                                    // this is to avoid readding textbox again and again.
                                    TextBox textBox = null;
                                    bool testBoxExists = ContentPanelCanvas.Children.Any(e => ((e as TextBox != null) && (Canvas.GetTop(e) == y) && (Canvas.GetLeft(e) == x)));

                                    if (testBoxExists)
                                    {
                                        textBox = ContentPanelCanvas.Children.First(e => ((e as TextBox != null) && (Canvas.GetTop(e) == y) && (Canvas.GetLeft(e) == x))) as TextBox;
                                    }
                                    if (textBox != null)
                                    {
                                        if (textBox.Text != content)
                                        {
                                            textBox.SelectionStart = textBox.Text.Length-1;
                                            textBox.Text = content;
                                        }
                                    }
                                    else
                                    {
                                        textBox = new TextBox();
                                        textBox.Text = content;
                                        // textBox.IsEnabled = false;
                                        ContentPanelCanvas.Children.Add(textBox);
                                        Canvas.SetLeft(textBox, x);
                                        Canvas.SetTop(textBox, y);
                                    }
                                });

                            }
                            else if (dataReceived.StartsWith("#JOINS#"))
                            {
                                // if received ipAddress is equal to localIP, do nothing, but wait for the admin to respond
                                // if we receive #ACCPT# response, then this user become part of group, if #DENYS# received,
                                // then this user is refused to be part of the group
                                // if no response received within timeout, means there is no other user and you are the group creator,
                                // set isAdmin to be true.
                                // going forward each time #JOINS# request comes and if you are the admin, you owe the responsibility to respond 
                                // with either #ACCPT# or #DENYS#
                                // if you are not the admin and if the #JOINS# request ipAddress is not equal to your ip address, you dont have any action, 
                                // you are just the participant in the group.

                                string sendersEmail = dataReceived.Split('#')[2].Trim('\0');
                                if (sendersEmail.Equals(loggedinUserEmail))
                                {
                                    //kick in timer for 3 seconds
                                    //if timer expires, that mean this user is the first
                                    // set isAdmin = true;
                                    // if someone responds, take appropriate action based on acceptance or deniance. 

                                    Deployment.Current.Dispatcher.BeginInvoke(
                                    () =>
                                    {
                                        ContentPanelCanvas.Visibility = Visibility.Collapsed;
                                        lableCanvas.Visibility = System.Windows.Visibility.Visible;
                                        waitForAdminTimer = new Timer(TimerCallback, null, 3000, Timeout.Infinite);
                                    });
                                }
                                else
                                {
                                    if (isAdmin)
                                    {
                                        string sendersName = GetContactName(sendersEmail);
                                        string response = "#WTADM#";
                                        if (!sendersName.Equals(string.Empty))
                                        {

                                            // if you are the admin, you immdeidately let everybody know that there is a group admin
                                            // and then let the admin user take his time to decide if he wants to 
                                            // allow or deny the request
                                            Deployment.Current.Dispatcher.BeginInvoke(
                                            () =>
                                            {
                                                response = "#WTADM#";  //Wait for Admin to respond

                                                SendString(response);

                                                MessageBoxResult isAllowed = MessageBox.Show("Your friend " + sendersName + " would like to join your discussion!", "Join Request", MessageBoxButton.OKCancel);


                                                if (isAllowed == MessageBoxResult.OK)
                                                {
                                                    response = "#ACCPT#";
                                                }
                                                else
                                                {
                                                    response = "#DENYS#Contact#";
                                                }

                                                SendString(response);
                                            });
                                        }
                                        else
                                        {
                                            response = "#DENYS#NotAContact#";
                                            SendString(response);
                                        }
                                    }
                                }
                            }
                            else if (dataReceived.StartsWith("#ACCPT#") && waitingForAcceptance)
                            {
                                Deployment.Current.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    responseReceived = true;
                                    ContentPanelCanvas.Visibility = Visibility.Visible;
                                    lableCanvas.Visibility = System.Windows.Visibility.Collapsed;
                                    waitingForAcceptance = false;
                                });
                            }
                            else if (dataReceived.StartsWith("#DENYS#") && waitingForAcceptance)
                            {
                                Deployment.Current.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    string contactOrNoContact = dataReceived.Split('#')[2].Trim('\0');
                                    responseReceived = true;
                                    _joined = false;
                                    if(contactOrNoContact.Equals("Contact"))
                                    {
                                        MessageBox.Show("Admin refused your request :(", "Request Refused", MessageBoxButton.OK);
                                    }
                                    else
                                    {
                                        MessageBox.Show("You dont seem to be a friend of the admin, you cannot join the discussion :(", "Request Refused", MessageBoxButton.OK);
                                    }
                                    NavigationService.Navigate(new Uri("/Login.xaml", UriKind.RelativeOrAbsolute));
                                });

                            }
                            else if (dataReceived.StartsWith("#WTADM#") && waitingForAcceptance)
                            {
                                Deployment.Current.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    waitForAdminTimer.Change(Timeout.Infinite, Timeout.Infinite);
                                });
                            }
                            else if (dataReceived.StartsWith("#FINIS#") && !isAdmin)
                            {
                                Deployment.Current.Dispatcher.BeginInvoke(
                                () =>
                                {
                                    MessageBox.Show("Admin has finished the discussion, exiting the whiteboard...", "Discussion finished", MessageBoxButton.OK);
                                    NavigationService.Navigate(new Uri("/Login.xaml", UriKind.RelativeOrAbsolute));
                                });
                            }
                            else
                            {
                                // Log it.
                                // Log(message, false);
                            }

                            finishedReceiving = false;
                            Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);

                            // Call receive again to continue to "listen" for the next message from the group
                            Receive();
                        }

                       
                    }, null);
            }
            else
            {
               // Log("Cannot receive. You are currently not joined to the group", true);
            }

            if (DeviceStatus.ApplicationCurrentMemoryUsage > 50000000)
            {
                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
                System.GC.Collect();
            }
        }

        private bool IsInContacts(string strEmail)
        {
            return true;
        }

        bool contactListReceived = false;
        string contactEmail;
        IDictionary<string, object> contactEmails;
        List<object> contacts = new List<object>();
        private string GetContactName(string strEmail)
        {
            SHA256 sha256 = new SHA256Managed();
            byte[] sha256Bytes = Encoding.UTF8.GetBytes((strEmail + "00000000480cc52e").ToLowerInvariant());
            byte[] cryString = sha256.ComputeHash(sha256Bytes);
            string hashedContactEmail = BitConverter.ToString(cryString).Replace("-", string.Empty).ToLowerInvariant();

            foreach (IDictionary<string, object> contact in contacts)
            {
                List<object> emailHashes = contact["email_hashes"] as List<object>;
                foreach (string emailHash in emailHashes)
                {
                    if (emailHash.Equals(hashedContactEmail))
                    {
                        return contact["first_name"].ToString();
                    }
                }
            }

            return string.Empty;
        }

        void ReadContactProperties_GetCompleted(object sender, LiveOperationCompletedEventArgs e)
        {
            object state = e.UserState;
            object error = e.Error;


            if (e.Error == null)
            {
                contacts = e.Result["data"] as List<object>;
            }
            else
            {
                // "Error calling API: " + e.Error.ToString();
            }
        }

        private void TimerCallback(object state)
        {
            // if no response received till the timerCallback is invoked, that means there is no one else on the group
            if (!responseReceived)
            {
                isAdmin = true;

                Deployment.Current.Dispatcher.BeginInvoke(
                () =>
                {
                    MessageBox.Show("You are the group creator and hence the administrator!", "Group Admin", MessageBoxButton.OK);
                    ContentPanelCanvas.Visibility = Visibility.Visible;
                    lableCanvas.Visibility = System.Windows.Visibility.Collapsed;
                    waitingForAcceptance = false;
                });

                LiveConnectClient readContact = new LiveConnectClient(client.Session);
                readContact.GetCompleted +=
                    new EventHandler<LiveOperationCompletedEventArgs>(ReadContactProperties_GetCompleted);
                readContact.GetAsync("me/contacts");
                int waitCount = 0;
                while (contacts.Count == 0 && waitCount < 5)
                {
                    Thread.Sleep(300);
                    waitCount++;
                }
            }
            else
            {
                isAdmin = false;
            }
        }
        /// <summary>
        /// Seperate all the coordinate serialized to string into seperate sets of line coordinates
        /// </summary>
        /// <param name="message">input string of serialized lines coordinates</param>
        /// <returns>Line coordinates for all the lines to be drawn</returns>
        private int[][] ReadReceivedCoordinates(string message)
        {
            string[] seperator = new string[] {Environment.NewLine, "$"};
            string[] lineCoords = message.Split(seperator, StringSplitOptions.RemoveEmptyEntries);
            List<int[]> returnLineCoords = new List<int[]>();

            foreach (string strCoords in lineCoords)
            {
                if (strCoords != string.Empty)
                {
                    string[] coords = strCoords.Split(',');
                    int[] arrCoords = new int[coords.Length];

                    int count = 0;
                    foreach (string coord in coords)
                    {
                        arrCoords[count] = Convert.ToInt32(coord);
                        count++;
                    }
                    returnLineCoords.Add(arrCoords);
                }
            }

            return returnLineCoords.ToArray();
        } 

        /// <summary>
        /// Wrapper over Draw function to get access to UI thread
        /// </summary>
        /// <param name="arrCoords">Line coordinates</param>
        /// <param name="isDraw">Type of line draw/erase</param>
        private void DrawLine(int [] arrCoords, bool isDraw, string lineColor, string lineThickness)
        {
            Deployment.Current.Dispatcher.BeginInvoke(
           () =>
           {
               Draw(arrCoords, isDraw, lineColor, lineThickness);
           });
        }

        /// <summary>
        /// Draw line
        /// </summary>
        /// <param name="arrCoords">Line coordinates</param>
        /// <param name="isDraw">Type of line draw/erase</param>
        private void Draw(int[] arrCoords, bool isDraw, string lineColor, string lineThickness)
        {

            Line line = new Line() { X1 = arrCoords[0], Y1 = arrCoords[1], X2 = arrCoords[2], Y2 = arrCoords[3] };

            if (isDraw)
            {
                line.Stroke = new SolidColorBrush(StringToColor(lineColor));
                line.StrokeThickness = StringToThickness(lineThickness);
            }
            else
            {
                line.Stroke = new SolidColorBrush(Colors.White);
                line.Cursor = Cursors.Eraser;
                line.StrokeThickness = StringToThickness(lineThickness);
            }
            
            
            this.ContentPanelCanvas.Children.Add(line);
        }

        private void ApplicationBarIconButton_Click(object sender, EventArgs e)
        {
            ApplicationBarIconButton temp = sender as ApplicationBarIconButton;
            switch(temp.Text)
            {
                case "color":
                    if (this.ContextMenuContentCanvas.Visibility == System.Windows.Visibility.Visible && this.Accents.Visibility == System.Windows.Visibility.Visible)
                    {
                        this.ContextMenuContentCanvas.Visibility = Visibility.Collapsed;
                        this.Accents.Visibility = System.Windows.Visibility.Collapsed;
                    }
                    else
                    {
                        this.Thicknesses.Visibility = System.Windows.Visibility.Collapsed;
                        this.Accents.Visibility = Visibility.Visible;
                        this.ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Visible;
                        this.ContextMenuContentCanvas.Opacity = 70;
                        ContextMenuContentCanvas.Height = 150;
                        // this.Accents.Open();
                    }
                    break;
                case "line thickness":
                    if (this.ContextMenuContentCanvas.Visibility == System.Windows.Visibility.Visible && this.Thicknesses.Visibility == System.Windows.Visibility.Visible)
                    {
                        this.ContextMenuContentCanvas.Visibility = Visibility.Collapsed;
                        this.Thicknesses.Visibility = System.Windows.Visibility.Collapsed;
                    }
                    else
                    {
                        this.Thicknesses.Visibility = Visibility.Visible;
                        this.Accents.Visibility = System.Windows.Visibility.Collapsed;
                        this.ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Visible;
                        this.ContextMenuContentCanvas.Opacity = 70;
                        // this.Accents.Open();
                    }
                    break;
                case "clear all":
                    COORD_BEGIN = "#RESET#";
                    SendString(COORD_BEGIN);
                    break;
            }
        }

        private void BlankRectangle_Hold(object sender, System.Windows.Input.GestureEventArgs e)
        {
            wbContextMenu.RenderTransformOrigin = e.GetPosition(this.ContentPanelCanvas);
            wbContextMenu.Visibility = System.Windows.Visibility.Visible;
            MenuItem menuItem = wbContextMenu.Items[0] as MenuItem;
            menuItem.CommandParameter = e.GetPosition(this.ContentPanelCanvas);

        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = (MenuItem)sender;

            switch(menuItem.Header.ToString())
            {
                case "Insert Text":

                    Point position = (Point)menuItem.CommandParameter;
                    TextBox textBox = new TextBox();
                    textBox.TextChanged +=new TextChangedEventHandler(textBox_TextChanged);
                    ContentPanelCanvas.Children.Add(textBox);
                    Canvas.SetLeft(textBox, position.X);
                    Canvas.SetTop(textBox, position.Y);

                    InputScope Keyboard = new InputScope();
                    InputScopeName ScopeName = new InputScopeName();
                    ScopeName.NameValue = InputScopeNameValue.Text;
                    Keyboard.Names.Add(ScopeName);
                    wbContextMenu.Visibility = System.Windows.Visibility.Collapsed;
                    // textBox.Focus();
                    textBox.InputScope = Keyboard;
                    textBox.Focus();
                    break;

                case "Erase":
                    COORD_BEGIN = "#ERASE#";
                    break;

                case "Draw":
                default:
                    COORD_BEGIN = "#CORDS#";
                    break;
            }

        }

        private void textBox_TextChanged(object sender, RoutedEventArgs e)
        {
            TextBox temp = (TextBox)sender;
            StringBuilder message = new StringBuilder();
            message.Append("#TEXTS#");
           

            message.Append(Canvas.GetLeft(temp).ToString());
            message.Append("#");
            message.Append(Canvas.GetTop(temp));
            message.Append("#");
            message.Append(temp.Text.Trim());

            SendString(message.ToString());
        }

        private void Accents_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListPicker temp = (ListPicker) sender;

            if (LINE_COLOR != temp.SelectedItem.ToString())
            {
                LINE_COLOR = temp.SelectedItem.ToString();
                ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Collapsed;
            }
        }

        private void Thicknesses_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ListPicker temp = (ListPicker)sender;
            LINE_THICK = temp.SelectedItem.ToString();
        }

        private void Thicknesses_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ListPicker temp = (ListPicker)sender;
            if (temp.RenderSize.Height != ContextMenuContentCanvas.Height)
                ContextMenuContentCanvas.Height = temp.RenderSize.Height + 30;

        }

        private void BlankRectangle_GotFocus(object sender, RoutedEventArgs e)
        {
            this.ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void Accents_LostFocus(object sender, RoutedEventArgs e)
        {
            this.ContextMenuContentCanvas.Visibility = System.Windows.Visibility.Collapsed;
        }

        private void ContentPanelCanvas_Unloaded(object sender, RoutedEventArgs e)
        {
            if (isAdmin)
            {
                //string message = "#FINIS#";
                //SendString(message);
            }
        }
    }
}